package cn.xiaolang.function.classloader;

import lombok.extern.slf4j.Slf4j;
import sun.misc.Launcher;

import java.net.URL;
import java.net.URLClassLoader;

@Slf4j
public class ClassLoaderDemo {

    public static void main(String[] args) {

        log.info("当前类的类加载器：{}", ClassLoaderDemo.class.getClassLoader());
        /**
         * 由于这些类是由引导类加载器(Bootstrap Classloader)进行加载的，
         * 而引导类加载器是有C++语言实现的，所以是无法访问的，故而该引用为NULL
         */
        log.info("Math类的类加载器：{}", Math.class.getClassLoader());

        /**
         * 获取一个系统的启动器，通过启动器获取类加载器，用来将class文件加载到内存中
         * 类加载器的实现机制，是基于双亲委托模型实现的，意味着：
         * AppClassLoader加载不到的类，会往父哪里ExtClassLoader的去加载
         * ExtClassLoader加载不到的类，会再往上级BootStrapClassLoader中去加载
         * BootStrapClassLoader记载不到的类，会抛出ClassNotFound似的异常
         */
        Launcher launcher = Launcher.getLauncher();
        log.info("JVM启动器有两种类加载器：");
        log.info("1.Launcher-AppClassLoader:{}", launcher.getClassLoader());
        log.info("2.Launcher-ExtClassLoader:{}", launcher.getClassLoader().getParent());
        log.info("3.Launcher-BootStrapClassLoader(由c++实现，无法访问):{}", launcher.getClassLoader().getParent().getParent());


        log.info("---No1.BootstrapClassLoader(引导类加载器)加载${JAVA_HOME}/jre/lib下的jar");
        URL[] urls = Launcher.getBootstrapClassPath().getURLs();
        for (URL url : urls)
            log.info(url.getPath());
        log.info("--------------------------------------------------------");

        log.info("---No2.ExtClassLoader(系统扩展类加载器)加载${JAVA_HOME}/jre/lib/ext下的jar");

        URLClassLoader extClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader().getParent();
        printUrl(extClassLoader);
        log.info("--------------------------------------------------------");

        log.info("---No3.AppClassLoader(应用级别的类加载器)加载classPath下的jar");
        URLClassLoader appClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
        printUrl(appClassLoader);
        log.info("--------------------------------------------------------");
    }

    private static void printUrl(URLClassLoader appClassLoader) {
        URL[] urls;
        log.info(appClassLoader.toString());
        urls = appClassLoader.getURLs();
        for (URL url : urls)
            log.info(url.getPath());
    }

}